/*
 * marketsim-eclipsetrader
 *
 * Copyright (C) 2008-2011 Steve Phelps and John Cartlidge
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 3 of
 * the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 */
package victria.marketsim.core;

import java.io.Serializable;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;

import org.apache.log4j.Logger;

public class MarketState implements Serializable {

	/**
	 * The complete set of outstanding orders.
	 */
	protected OrderBook completeOrderBook;
	
	/**
	 * The subset of the outstanding orders that are 
	 * visible to all traders.
	 */
	protected OrderBook visibleOrderBook;
	
	protected HashMap<Object,List<Order>> ordersByTrader;
	protected HashMap<Long,Order> ordersById;

	static Logger logger = Logger.getLogger(MarketState.class);
	
	public MarketState() {
		completeOrderBook = new OrderBook();
		visibleOrderBook = new OrderBook();
		ordersByTrader = new HashMap<Object,List<Order>>();
		ordersById = new HashMap<Long,Order>();
	}		
	
	public Spread getSpread() {
		return visibleOrderBook.getSpread();
	}
	

	public void add(Order order) {
		logger.debug("Adding order " + order.toString());
		if (order.isVisible()) {
			if (visibleOrderBook.add(order, this)) {
				completeOrderBook.add(order, this);
			} 
		} else {
			completeOrderBook.add(order, this);
		}
		List<Order> orders = ordersByTrader.get(order.getTrader());
		if (orders == null) {
			orders = new LinkedList<Order>();
			ordersByTrader.put(order.getTrader(), orders);
		}
		orders.add(order);
		ordersById.put(order.getId(), order);
	}

	public boolean remove(Order order) {
		synchronized(this) {
			logger.info("Removing order " + order.toPrettyString());
			List<Order> tradersOrders = ordersByTrader.get(order.getTrader());
			if (tradersOrders != null) {
				tradersOrders.remove(order);
			}
			ordersById.remove(order.getId());
			boolean result = completeOrderBook.remove(order);
			if (order.isVisible()) {
				visibleOrderBook.remove(order);
			}			
			return result;
		}
	}

	public List<Order> getAsks() {
		return completeOrderBook.getAsks();
	}

	public List<Order> getBids() {
		return completeOrderBook.getBids();
	}

	public boolean isEmpty() {
		return completeOrderBook.isEmpty();
	}
	
	public boolean contains(Order order) {
		return completeOrderBook.contains(order);
	}

	
	public List<Order> getVisibleAsks() {
		return visibleOrderBook.getAsks();
	}
	
	public List<Order> getVisibleBids() {
		return visibleOrderBook.getBids();
	}

	public List<Order> getOrders(Object trader) {
		return ordersByTrader.get(trader);
	}
	
	public List<Order> getAllOrders() {
		return completeOrderBook.getAllOrders();
	}
	
	public Order getOrder(long id) {
		return ordersById.get(id);
	}
	
	public boolean isOutstanding(long id) {
//		logger.debug("Checking to see if order id " + id + " is outstanding..");
//		logger.debug("ordersById = " + ordersById);
//		logger.debug("bids = " + bids);
//		logger.debug("asks = " + asks);
		boolean result = ordersById.containsKey(id);
//		logger.debug("result = " + result);
		return result;
	}
	
	public OrderBook getVisibleOrderBook() {
		return visibleOrderBook;
	}

	public void setVisibleOrderBook(OrderBook visibleOrderBook) {
		this.visibleOrderBook = visibleOrderBook;
	}

	public void setCompleteOrderBook(OrderBook completeOrderBook) {
		this.completeOrderBook = completeOrderBook;
	}


	public String toString() {
		return "(" + getClass() + " completeOrderBook:" + completeOrderBook + " visibleOrderBook:" + visibleOrderBook + ")";
	}
		
	
}
